package tests;

import static org.junit.Assert.*;

import java.util.Collection;
import java.util.Date;

import javax.sql.rowset.Predicate;

import model.LectureService;
import model.LectureServiceListener;
import model.Lesson;
import model.ServiceFactory;
import model.Student;
import model.StudentService;
import model.impl.LectureServiceImpl;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;

public class LectureServiceTest
{
	class LectureServiceListenerTest implements LectureServiceListener
	{
		public boolean invoked;
		public Collection<Lesson> added;
		public Collection<Lesson> removed;
		public LectureServiceListenerTest()
		{
			invoked = false;
		}
		
		
		@Override
		public void onLessonsChanged(Collection<Lesson> added,
				Collection<Lesson> removed)
		{
			// TODO Auto-generated method stub
			invoked = true;
			this.added = added;
			this.removed = removed;
		}
	}
	
	abstract class LectureServiceListenerPredicate<T extends LectureServiceListenerTest> implements tests.Predicate<LectureServiceListener>
	{		
		protected  T listener;
		public LectureServiceListenerPredicate(T listener)
		{
			this.listener = listener;
		}
		@Override
		public boolean evaluate()
		{
			// TODO Auto-generated method stub
			return false;
		}
	}
	
	class AddNewLessonPredicate extends LectureServiceListenerPredicate
	{
		public AddNewLessonPredicate(LectureServiceListenerTest lslt)
		{
			super(lslt);
		}
		@Override
		public boolean evaluate()
		{
			// TODO Auto-generated method stub
			boolean res = listener.invoked;
			res = res && this.listener.added.size() == 1 && this.listener.removed.isEmpty();
			
			return res;
		}
	}
	
	class RequestLessonsPredicate extends LectureServiceListenerPredicate<LectureServiceListenerTest>
	{
		public RequestLessonsPredicate(LectureServiceListenerTest lslt)
		{
			super(lslt);
		}
		
		@Override
		public boolean evaluate()
		{
			// TODO Auto-generated method stub
			boolean res = this.listener.invoked;
			res = res && this.listener.removed.isEmpty() && this.listener.added.size() >= 1;
			return res;
		}
	}
	
	class UpdateLessonPredicate extends LectureServiceListenerPredicate<LectureServiceListenerTest>
	{
		public UpdateLessonPredicate(LectureServiceListenerTest lslt)
		{
			super(lslt);
		}
		
		@Override
		public boolean evaluate()
		{
			// TODO Auto-generated method stub
			boolean res = this.listener.invoked;
			res = res && this.listener.removed.size() == 1 && this.listener.added.size() == 1;
			return res;
		}
	}
	
	LectureService service;
	LectureServiceListenerTest serviceListener;
	
	@Before
	public void setUp() throws ClassNotFoundException
	{
		service = ServiceFactory.getInstance().getService(LectureService.class);
		assertNotNull(service);
		assertTrue(service instanceof LectureServiceImpl);
		
		serviceListener = new LectureServiceListenerTest();
		assertFalse(serviceListener.invoked);
		service.addLectureServiceObserver(serviceListener);		
	}
	
	@After
	public void tearDown()
	{
		service.removeLectureServiceObserver(serviceListener);
	}
	
	@Test(timeout = 10000)
	public void testAddNewLesson() throws InterruptedException
	{
		Student student = Mockito.mock(Student.class);
		Mockito.when(student.getId()).thenReturn(1);
		Mockito.when(student.getName()).thenReturn("Pera");
		
		assertEquals(student.getId(), 1);
		assertEquals(student.getName(), "Pera");
		
		AddNewLessonPredicate predicate = new AddNewLessonPredicate(serviceListener);
		
		String title = "title";
		String content = "content";
		int income = 1000;
		Date date = new Date();
		
		service.addNewLesson(student, title, content, date, income);
		while(!serviceListener.invoked)
		{
			System.out.println("waiting for listener to be invoked...");
			Thread.sleep(20);
		}
		
		assertTrue(predicate.evaluate());
		Lesson l = (Lesson)serviceListener.added.iterator().next();
		
		assertNotNull(l);
		assertEquals(income, l.getIncome());
		assertEquals(content, l.getContent());
		assertEquals(title, l.getTitle());
		assertEquals(date, l.getDate());
	}
	
	@Test(timeout = 10000)
	public void testRequestLessons()  throws InterruptedException
	{
		RequestLessonsPredicate predicate = new RequestLessonsPredicate(serviceListener);
		service.requestAllLessons();
		
		while(!serviceListener.invoked)
		{
			Thread.sleep(20);
		}
		
		assertTrue(predicate.evaluate());
	}
	
	@Test
	public void testUpdateLesson() throws InterruptedException
	{
	}
}
